package com.zzg.mybatis.generator.controller;

import com.roin.util.code.generator.DefaultConfig;
import com.roin.util.code.generator.controller.ControllerConfigController;
import com.roin.util.code.generator.controller.HtmlConfigController;
import com.roin.util.code.generator.model.BusinessGeneratorConfig;
import com.roin.util.code.generator.model.HtmlConfigColumn;
import com.roin.util.code.generator.util.FreemarkerManager;
import com.zzg.mybatis.generator.bridge.MybatisGeneratorBridge;
import com.zzg.mybatis.generator.model.DatabaseConfig;
import com.zzg.mybatis.generator.model.GeneratorConfig;
import com.zzg.mybatis.generator.model.UITableColumnVO;
import com.zzg.mybatis.generator.util.ConfigHelper;
import com.zzg.mybatis.generator.util.DbUtil;
import com.zzg.mybatis.generator.util.MyStringUtils;
import com.zzg.mybatis.generator.view.AlertUtil;
import com.zzg.mybatis.generator.view.UIProgressCallback;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.stage.DirectoryChooser;
import javafx.util.Callback;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.mybatis.generator.config.ColumnOverride;
import org.mybatis.generator.config.IgnoredColumn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.io.File;
import java.net.URL;
import java.sql.SQLRecoverableException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;

public class MainUIController extends BaseFXController {

    private static final Logger _LOG = LoggerFactory.getLogger(MainUIController.class);
    private static final String FOLDER_NO_EXIST = "部分目录不存在，是否创建";
    // tool bar buttons
    @FXML
    private Label connectionLabel;
    @FXML
    private Label configsLabel;
    @FXML
    private TextField modelTargetPackage;
    @FXML
    private TextField mapperTargetPackage;
    @FXML
    private TextField daoTargetPackage;
    @FXML
    private TextField tableNameField;
    @FXML
    private TextField domainObjectNameField;
    @FXML
    private TextField generateKeysField;    //主键ID
    @FXML
    private TextField modelTargetProject;
    @FXML
    private TextField mappingTargetProject;
    @FXML
    private TextField daoTargetProject;
    @FXML
    private TextField mapperName;
    @FXML
    private TextField projectFolderField;
    @FXML
    private CheckBox offsetLimitCheckBox;
    @FXML
    private CheckBox commentCheckBox;
    @FXML
    private CheckBox overrideXML;
    @FXML
    private CheckBox needToStringHashcodeEquals;
    @FXML
    private CheckBox forUpdateCheckBox;
    @FXML
    private CheckBox annotationDAOCheckBox;
    @FXML
    private CheckBox useTableNameAliasCheckbox;
    @FXML
    private CheckBox annotationCheckBox;
    @FXML
    private CheckBox useActualColumnNamesCheckbox;
    @FXML
    private CheckBox useExample;
    @FXML
    private CheckBox useDAOExtendStyle;
    @FXML
    private CheckBox useSchemaPrefix;
    @FXML
    private CheckBox jsr310Support;
    @FXML
    private TreeView<String> leftDBTree;
    // Current selected databaseConfig
    private DatabaseConfig selectedDatabaseConfig;
    // Current selected tableName
    private String tableName;

    private List<IgnoredColumn> ignoredColumns;

    private List<ColumnOverride> columnOverrides;

    @FXML
    private ChoiceBox<String> encodingChoice;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        ImageView dbImage = new ImageView("icons/computer.png");
        dbImage.setFitHeight(40);
        dbImage.setFitWidth(40);
        connectionLabel.setGraphic(dbImage);
        connectionLabel.setOnMouseClicked(event -> {
            DbConnectionController controller = (DbConnectionController) loadFXMLPage("新建数据库连接", FXMLPage.NEW_CONNECTION, false);
            controller.setMainUIController(this);
            controller.showDialogStage();
        });
        ImageView configImage = new ImageView("icons/config-list.png");
        configImage.setFitHeight(40);
        configImage.setFitWidth(40);
        configsLabel.setGraphic(configImage);
        configsLabel.setOnMouseClicked(event -> {
            GeneratorConfigController controller = (GeneratorConfigController) loadFXMLPage("配置", FXMLPage.GENERATOR_CONFIG, false);
            controller.setMainUIController(this);
            controller.showDialogStage();
        });

        leftDBTree.setShowRoot(false);
        leftDBTree.setRoot(new TreeItem<>());
        Callback<TreeView<String>, TreeCell<String>> defaultCellFactory = TextFieldTreeCell.forTreeView();
        leftDBTree.setCellFactory((TreeView<String> tv) -> {
            TreeCell<String> cell = defaultCellFactory.call(tv);
            cell.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
                int level = leftDBTree.getTreeItemLevel(cell.getTreeItem());
                TreeCell<String> treeCell = (TreeCell<String>) event.getSource();
                TreeItem<String> treeItem = treeCell.getTreeItem();
                if (level == 1) {
                    final ContextMenu contextMenu = new ContextMenu();
                    MenuItem item1 = new MenuItem("关闭连接");
                    item1.setOnAction(event1 -> treeItem.getChildren().clear());
                    MenuItem item2 = new MenuItem("编辑连接");
                    item2.setOnAction(event1 -> {
                        DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
                        DbConnectionController controller = (DbConnectionController) loadFXMLPage("编辑数据库连接", FXMLPage.NEW_CONNECTION, false);
                        controller.setMainUIController(this);
                        controller.setConfig(selectedConfig);
                        controller.showDialogStage();
                    });
                    MenuItem item3 = new MenuItem("删除连接");
                    item3.setOnAction(event1 -> {
                        DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
                        try {
                            ConfigHelper.deleteDatabaseConfig(selectedConfig);
                            this.loadLeftDBTree();
                        } catch (Exception e) {
                            AlertUtil.showErrorAlert("Delete connection failed! Reason: " + e.getMessage());
                        }
                    });
                    contextMenu.getItems().addAll(item1, item2, item3);
                    cell.setContextMenu(contextMenu);
                }
                if (event.getClickCount() == 2) {
                    if (treeItem == null) {
                        return;
                    }
                    treeItem.setExpanded(true);
                    if (level == 1) {
                        System.out.println("index: " + leftDBTree.getSelectionModel().getSelectedIndex());
                        DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
                        try {
                            List<String> tables = DbUtil.getTableNames(selectedConfig);
                            if (tables != null && tables.size() > 0) {
                                ObservableList<TreeItem<String>> children = cell.getTreeItem().getChildren();
                                children.clear();
                                for (String tableName : tables) {
                                    TreeItem<String> newTreeItem = new TreeItem<>();
                                    ImageView imageView = new ImageView("icons/table.png");
                                    imageView.setFitHeight(16);
                                    imageView.setFitWidth(16);
                                    newTreeItem.setGraphic(imageView);
                                    newTreeItem.setValue(tableName);
                                    children.add(newTreeItem);
                                }
                            }
                        } catch (SQLRecoverableException e) {
                            _LOG.error(e.getMessage(), e);
                            AlertUtil.showErrorAlert("连接超时");
                        } catch (Exception e) {
                            _LOG.error(e.getMessage(), e);
                            AlertUtil.showErrorAlert(e.getMessage());
                        }
                    } else if (level == 2) { // left DB tree level3
                        String tableName = treeCell.getTreeItem().getValue();
                        selectedDatabaseConfig = (DatabaseConfig) treeItem.getParent().getGraphic().getUserData();
                        this.tableName = tableName;
                        tableNameField.setText(tableName);
                        domainObjectNameField.setText(MyStringUtils.dbStringToCamelStyle(tableName));
                        mapperName.setText(domainObjectNameField.getText().concat("Mapper"));
                    }
                }
            });
            return cell;
        });
        loadLeftDBTree();
        setTooltip();
        //默认选中第一个，否则如果忘记选择，没有对应错误提示
        encodingChoice.getSelectionModel().selectFirst();

        initializeCustom();
    }


    private void setTooltip() {
        encodingChoice.setTooltip(new Tooltip("生成文件的编码，必选"));
        generateKeysField.setTooltip(new Tooltip("insert时可以返回主键ID"));
        offsetLimitCheckBox.setTooltip(new Tooltip("是否要生成分页查询代码"));
        commentCheckBox.setTooltip(new Tooltip("使用数据库的列注释作为实体类字段名的Java注释 "));
        useActualColumnNamesCheckbox.setTooltip(new Tooltip("是否使用数据库实际的列名作为实体类域的名称"));
        useTableNameAliasCheckbox.setTooltip(new Tooltip("在Mapper XML文件中表名使用别名，并且列全部使用as查询"));
        overrideXML.setTooltip(new Tooltip("重新生成时把原XML文件覆盖，否则是追加"));
        useDAOExtendStyle.setTooltip(new Tooltip("将通用接口方法放在公共接口中，DAO接口留空"));
        forUpdateCheckBox.setTooltip(new Tooltip("在Select语句中增加for update后缀"));
    }

    void loadLeftDBTree() {
        TreeItem rootTreeItem = leftDBTree.getRoot();
        rootTreeItem.getChildren().clear();
        try {
            List<DatabaseConfig> dbConfigs = ConfigHelper.loadDatabaseConfig();
            for (DatabaseConfig dbConfig : dbConfigs) {
                TreeItem<String> treeItem = new TreeItem<>();
                treeItem.setValue(dbConfig.getName());
                ImageView dbImage = new ImageView("icons/computer.png");
                dbImage.setFitHeight(16);
                dbImage.setFitWidth(16);
                dbImage.setUserData(dbConfig);
                treeItem.setGraphic(dbImage);
                rootTreeItem.getChildren().add(treeItem);
            }
        } catch (Exception e) {
            _LOG.error("connect db failed, reason: {}", e);
            AlertUtil.showErrorAlert(e.getMessage() + "\n" + ExceptionUtils.getStackTrace(e));
        }
    }

    @FXML
    public void chooseProjectFolder() {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        File selectedFolder = directoryChooser.showDialog(getPrimaryStage());
        if (selectedFolder != null) {
            projectFolderField.setText(selectedFolder.getAbsolutePath());
        }
    }

    @FXML
    public void generateCode() {
        if (tableName == null) {
            AlertUtil.showWarnAlert("请先在左侧选择数据库表");
            return;
        }
        
        if (modelCheckBox.isSelected()){
            String result = validateConfig();
            if (result != null) {
                AlertUtil.showErrorAlert(result);
                return;
            }
            GeneratorConfig generatorConfig = getGeneratorConfigFromUI();
            if (!checkDirs(generatorConfig)) {
                return;
            }

            MybatisGeneratorBridge bridge = new MybatisGeneratorBridge();
            bridge.setGeneratorConfig(generatorConfig);
            bridge.setDatabaseConfig(selectedDatabaseConfig);
            bridge.setIgnoredColumns(ignoredColumns);
            bridge.setColumnOverrides(columnOverrides);
//            UIProgressCallback alert = new UIProgressCallback(Alert.AlertType.INFORMATION);
//            bridge.setProgressCallback(alert);
//            alert.show();
            try {
                bridge.generate();
            } catch (Exception e) {
                e.printStackTrace();
                AlertUtil.showErrorAlert(e.getMessage());
            }
        }

        resetGeneratorConfigFromUI();
        String filePath;
        try {
            if (businessGeneratorConfig.isController()){
                filePath = businessGeneratorConfig.getProjectFolder()+File.separator+businessGeneratorConfig.getControllerTargetProject()+File.separator+
                        businessGeneratorConfig.getControllerPackage().replace(".",File.separator);
                if (!checkFile(filePath)){
                    return;
                }
                //生成Controller类
                FreemarkerManager.outToFile(DefaultConfig.getControllerTemplateName(),businessGeneratorConfig,filePath+File.separator+businessGeneratorConfig.getModelName()+"Controller.java");
                _LOG.info("生成Controller成功！");
            }
        }catch (Exception e){
            _LOG.error("生成Controller异常",e);
        }
        try {
            if (businessGeneratorConfig.isService()) {
                filePath = businessGeneratorConfig.getProjectFolder() + File.separator + businessGeneratorConfig.getServiceTargetProject() + File.separator +
                        businessGeneratorConfig.getServicePackage().replace(".", File.separator);
                if (!checkFile(filePath)) {
                    return;
                }
                //生成Service接口
                FreemarkerManager.outToFile(DefaultConfig.getServiceTemplateName(),businessGeneratorConfig,filePath+File.separator+businessGeneratorConfig.getModelName()+"Service.java");
                filePath =businessGeneratorConfig.getProjectFolder()+File.separator+businessGeneratorConfig.getServiceTargetProject()+File.separator+
                        businessGeneratorConfig.getServicePackage().replace(".",File.separator)+File.separator+"impl"+File.separator;
                if (!checkFile(filePath)){
                    return;
                }
                //生成Service实现类
                FreemarkerManager.outToFile(DefaultConfig.getServiceImplTemplateName(),businessGeneratorConfig,filePath+File.separator+businessGeneratorConfig.getModelName()+"ServiceImpl.java");
                _LOG.info("生成Service成功！");
            }
        }catch (Exception e){
            _LOG.error("生成Service异常",e);
        }

        try {
            if (businessGeneratorConfig.isHtml()){
                filePath = businessGeneratorConfig.getHtmlFolder() + File.separator + businessGeneratorConfig.getModelSnakeName();
                if (!checkFile(filePath)) {
                    return;
                }
                List<HtmlConfigColumn> columns = businessGeneratorConfig.getHtmlConfig().getColumns();
                if (!tableName.equalsIgnoreCase(businessGeneratorConfig.getHtmlConfig().getTableName()) || columns==null || columns.isEmpty()){
                    businessGeneratorConfig.getHtmlConfig().setColumns(getHtmlConfigColumns());
                }
                //生成Html实现类
                FreemarkerManager.outToFile(DefaultConfig.getHtmlTemplateName(),businessGeneratorConfig,filePath+File.separator+"list.html");
                if (businessGeneratorConfig.getHtmlConfig().isNeedAddForm() || businessGeneratorConfig.getHtmlConfig().isNeedEditForm()){
                    //生成Add表单
                    FreemarkerManager.outToFile(DefaultConfig.getHtmlAddTemplateName(),businessGeneratorConfig.getHtmlConfig(),filePath+File.separator+"add.html");
                }
                _LOG.info("生成Html成功！");
            }
        }catch (Exception e){
            _LOG.error("生成Html异常",e);
        }


        AlertUtil.showInfoAlert("生成代码完成！若部分代码未生成，请查看日志文件logs/error.log 。");
    }

    private boolean checkFile(String filePath){
        File file = new File(filePath);
        if (!file.exists()){
            Alert alert = AlertUtil.buildConfirmationAlert("路径：" + filePath + "不存在，是否创建目录？");
            Optional<ButtonType> optional= alert.showAndWait();
            if (optional.isPresent() && optional.get().getButtonData()== ButtonBar.ButtonData.OK_DONE){
                file.mkdirs();
            }else {
                return false;
            }
        }
        if (!file.isDirectory()) {
            AlertUtil.showErrorAlert("路径：" + filePath + "不是一个目录，请检查！");
            return false;
        }
        return true;
    }

    private String validateConfig() {
        String projectFolder = projectFolderField.getText();
        if (StringUtils.isEmpty(projectFolder)) {
            return "项目目录不能为空";
        }
        if (modelCheckBox.isSelected()){
            if (StringUtils.isEmpty(domainObjectNameField.getText())) {
                return "类名不能为空";
            }
            if (StringUtils.isAnyEmpty(modelTargetPackage.getText(), mapperTargetPackage.getText(), daoTargetPackage.getText())) {
                return "实体类包名、Mapper接口包名、Mapper存放目录都不能为空";
            }
        }
        if (htmlCheckBox.isSelected()){
            if (StringUtils.isEmpty(htmlFolderField.getText())) {
                return "HTML所在目录不能为空";
            }
        }
        if (controllerCheckBox.isSelected()){
            if (StringUtils.isAnyEmpty(controllerPackageField.getText(), controllerTargetProject.getText())) {
                return "Controller包名、Controller存放目录都不能为空";
            }
        }
        if (serviceCheckBox.isSelected()){
            if (StringUtils.isAnyEmpty(servicePackageField.getText(), serviceTargetProject.getText())) {
                return "Service包名、Service存放目录都不能为空";
            }
        }
        return null;
    }

    @FXML
    public void saveGeneratorConfig() {
        TextInputDialog dialog = new TextInputDialog(businessGeneratorConfig.getName());
        dialog.setTitle("保存当前配置");
        dialog.setContentText("请输入配置名称");
        Optional<String> result = dialog.showAndWait();
        if (result.isPresent()) {
            String name = result.get();
            if (StringUtils.isEmpty(name)) {
                AlertUtil.showErrorAlert("名称不能为空");
                return;
            }
            _LOG.info("user choose name: {}", name);
            try {
                GeneratorConfig generatorConfig = getGeneratorConfigFromUI();
                generatorConfig.setName(name);
                ConfigHelper.saveGeneratorConfig(generatorConfig);
                //add by roin
                resetGeneratorConfigFromUI();
                businessGeneratorConfig.setName(name);
                ConfigHelper.saveBusinessGeneratorConfig(businessGeneratorConfig);
            } catch (Exception e) {
                _LOG.error("保存配置失败",e);
                AlertUtil.showErrorAlert("保存配置失败");
            }
        }
    }

    public GeneratorConfig getGeneratorConfigFromUI() {
        GeneratorConfig generatorConfig = new GeneratorConfig();
        generatorConfig.setProjectFolder(projectFolderField.getText());
        generatorConfig.setModelPackage(modelTargetPackage.getText());
        generatorConfig.setGenerateKeys(generateKeysField.getText());
        generatorConfig.setModelPackageTargetFolder(modelTargetProject.getText());
        generatorConfig.setDaoPackage(daoTargetPackage.getText());
        generatorConfig.setDaoTargetFolder(daoTargetProject.getText());
        generatorConfig.setMapperName(mapperName.getText());
        generatorConfig.setMappingXMLPackage(mapperTargetPackage.getText());
        generatorConfig.setMappingXMLTargetFolder(mappingTargetProject.getText());
        generatorConfig.setTableName(tableNameField.getText());
        generatorConfig.setDomainObjectName(domainObjectNameField.getText());
        generatorConfig.setOffsetLimit(offsetLimitCheckBox.isSelected());
        generatorConfig.setComment(commentCheckBox.isSelected());
        generatorConfig.setOverrideXML(overrideXML.isSelected());
        generatorConfig.setNeedToStringHashcodeEquals(needToStringHashcodeEquals.isSelected());
        generatorConfig.setUseTableNameAlias(useTableNameAliasCheckbox.isSelected());
        generatorConfig.setNeedForUpdate(forUpdateCheckBox.isSelected());
        generatorConfig.setAnnotationDAO(annotationDAOCheckBox.isSelected());
        generatorConfig.setAnnotation(annotationCheckBox.isSelected());
        generatorConfig.setUseActualColumnNames(useActualColumnNamesCheckbox.isSelected());
        generatorConfig.setEncoding(encodingChoice.getValue());
        generatorConfig.setUseExample(useExample.isSelected());
        generatorConfig.setUseDAOExtendStyle(useDAOExtendStyle.isSelected());
        generatorConfig.setUseSchemaPrefix(useSchemaPrefix.isSelected());
        generatorConfig.setJsr310Support(jsr310Support.isSelected());
        return generatorConfig;
    }

    public void setGeneratorConfigIntoUI(GeneratorConfig generatorConfig) {
        projectFolderField.setText(generatorConfig.getProjectFolder());
        modelTargetPackage.setText(generatorConfig.getModelPackage());
        generateKeysField.setText(generatorConfig.getGenerateKeys());
        domainObjectNameField.setText(generatorConfig.getDomainObjectName());
        modelTargetProject.setText(generatorConfig.getModelPackageTargetFolder());
        daoTargetPackage.setText(generatorConfig.getDaoPackage());
        daoTargetProject.setText(generatorConfig.getDaoTargetFolder());
        mapperTargetPackage.setText(generatorConfig.getMappingXMLPackage());
        mappingTargetProject.setText(generatorConfig.getMappingXMLTargetFolder());
        mapperName.setText(generatorConfig.getMapperName());
        encodingChoice.setValue(generatorConfig.getEncoding());
        useExample.setSelected(generatorConfig.isUseExample());
        offsetLimitCheckBox.setSelected(generatorConfig.isOffsetLimit());
        commentCheckBox.setSelected(generatorConfig.isComment());
        overrideXML.setSelected(generatorConfig.isOverrideXML());
        needToStringHashcodeEquals.setSelected(generatorConfig.isNeedToStringHashcodeEquals());
        useSchemaPrefix.setSelected(generatorConfig.isUseSchemaPrefix());
        forUpdateCheckBox.setSelected(generatorConfig.isNeedForUpdate());
        annotationDAOCheckBox.setSelected(generatorConfig.isAnnotationDAO());
        useDAOExtendStyle.setSelected(generatorConfig.isUseDAOExtendStyle());
        jsr310Support.setSelected(generatorConfig.isJsr310Support());
        annotationCheckBox.setSelected(generatorConfig.isAnnotation());
        useActualColumnNamesCheckbox.setSelected(generatorConfig.isUseActualColumnNames());
        useTableNameAliasCheckbox.setSelected(generatorConfig.isUseTableNameAlias());
        //add by roin
        try {
            BusinessGeneratorConfig temp = ConfigHelper.loadBusinessGeneratorConfig(generatorConfig.getName());
            if (temp!=null){
                businessGeneratorConfig = temp;
                rerenderBusinessConfig();
            }

        }catch (Exception e){
            _LOG.error("加载配置"+generatorConfig.getName()+"异常",e);
        }
        
    }

    @FXML
    public void openTableColumnCustomizationPage() {
        if (tableName == null) {
            AlertUtil.showWarnAlert("请先在左侧选择数据库表");
            return;
        }
        SelectTableColumnController controller = (SelectTableColumnController) loadFXMLPage("定制列", FXMLPage.SELECT_TABLE_COLUMN, true);
        controller.setMainUIController(this);
        try {
            // If select same schema and another table, update table data
            if (!tableName.equals(controller.getTableName())) {
                List<UITableColumnVO> tableColumns = DbUtil.getTableColumns(selectedDatabaseConfig, tableName);
                controller.setColumnList(FXCollections.observableList(tableColumns));
                controller.setTableName(tableName);
            }
            controller.showDialogStage();
        } catch (Exception e) {
            _LOG.error(e.getMessage(), e);
            AlertUtil.showErrorAlert(e.getMessage());
        }
    }

    public void setIgnoredColumns(List<IgnoredColumn> ignoredColumns) {
        this.ignoredColumns = ignoredColumns;
    }

    public void setColumnOverrides(List<ColumnOverride> columnOverrides) {
        this.columnOverrides = columnOverrides;
    }

    /**
     * 检查并创建不存在的文件夹
     *
     * @return
     */
    private boolean checkDirs(GeneratorConfig config) {
        List<String> dirs = new ArrayList<>();
        dirs.add(config.getProjectFolder());
        dirs.add(FilenameUtils.normalize(config.getProjectFolder().concat("/").concat(config.getModelPackageTargetFolder())));
        dirs.add(FilenameUtils.normalize(config.getProjectFolder().concat("/").concat(config.getDaoTargetFolder())));
        dirs.add(FilenameUtils.normalize(config.getProjectFolder().concat("/").concat(config.getMappingXMLTargetFolder())));
        boolean haveNotExistFolder = false;
        for (String dir : dirs) {
            File file = new File(dir);
            if (!file.exists()) {
                haveNotExistFolder = true;
            }
        }
        if (haveNotExistFolder) {
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
            alert.setContentText(FOLDER_NO_EXIST);
            Optional<ButtonType> optional = alert.showAndWait();
            if (optional.isPresent()) {
                if (ButtonType.OK == optional.get()) {
                    try {
                        for (String dir : dirs) {
                            FileUtils.forceMkdir(new File(dir));
                        }
                        return true;
                    } catch (Exception e) {
                        AlertUtil.showErrorAlert("创建目录失败，请检查目录是否是文件而非目录");
                    }
                } else {
                    return false;
                }
            }
        }
        return true;
    }

    @FXML
    public void openTargetFolder() {
        GeneratorConfig generatorConfig = getGeneratorConfigFromUI();
        String projectFolder = generatorConfig.getProjectFolder();
        try {
            Desktop.getDesktop().browse(new File(projectFolder).toURI());
        } catch (Exception e) {
            AlertUtil.showErrorAlert("打开目录失败，请检查目录是否填写正确" + e.getMessage());
        }

    }

    /*-------------------------------定制部分---------------------------------------*/
    @FXML
    private TextField htmlFolderField;
    @FXML
    private TextField controllerTargetProject;
    @FXML
    private TextField serviceTargetProject;
    @FXML
    private TextField controllerPackageField;
    @FXML
    private TextField servicePackageField;
    @FXML
    private CheckBox modelCheckBox;
    @FXML
    private CheckBox htmlCheckBox;
    @FXML
    private CheckBox controllerCheckBox;
    @FXML
    private CheckBox serviceCheckBox;
    @FXML
    private TextField moduleField;
    @FXML
    private TextField authorField;
    @FXML
    private Button htmlConfigButton;
    @FXML
    private Button controllerConfigButton;
    private BusinessGeneratorConfig businessGeneratorConfig = new BusinessGeneratorConfig();

    private void initializeCustom() {
        htmlCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
            htmlFolderField.setEditable(newValue);
            htmlConfigButton.setDisable(!newValue);
        });
        controllerCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
            controllerPackageField.setEditable(newValue);
            controllerConfigButton.setDisable(!newValue);
        });

        modelCheckBox.setTooltip(new Tooltip("是否生成Model代码"));
        htmlCheckBox.setTooltip(new Tooltip("是否生成Html代码"));
        controllerCheckBox.setTooltip(new Tooltip("是否要生成Controller代码"));
        serviceCheckBox.setTooltip(new Tooltip("是否要生成Service代码"));
    }
    private void rerenderBusinessConfig(){
        htmlFolderField.setText(businessGeneratorConfig.getHtmlFolder());
        controllerTargetProject.setText(businessGeneratorConfig.getControllerTargetProject());
        controllerPackageField.setText(businessGeneratorConfig.getControllerPackage());
        serviceTargetProject.setText(businessGeneratorConfig.getServiceTargetProject());
        servicePackageField.setText(businessGeneratorConfig.getServicePackage());

        htmlCheckBox.setSelected(businessGeneratorConfig.isHtml());
        controllerCheckBox.setSelected(businessGeneratorConfig.isController());
        serviceCheckBox.setSelected(businessGeneratorConfig.isService());
        modelCheckBox.setSelected(businessGeneratorConfig.isModel());

        moduleField.setText(businessGeneratorConfig.getModule());
        authorField.setText(businessGeneratorConfig.getAuthor());
    }
    private void resetGeneratorConfigFromUI(){
        String projectDir =  projectFolderField.getText();
        String htmlDir =  htmlFolderField.getText();
        String controllerTarget =  controllerTargetProject.getText();
        String controllerPackage =  controllerPackageField.getText();
        String servicePackage =  servicePackageField.getText();
        String serviceTarget =  serviceTargetProject.getText();
        String daoPackage =  daoTargetPackage.getText();
        String daoName =  mapperName.getText();
        String daoFullName =  daoPackage+"."+daoName;
        String modelPackage =  modelTargetPackage.getText();
        String modelName =  domainObjectNameField.getText();
        String modelFullName =  modelPackage+"."+modelName;
        String module =  moduleField.getText();
        String author =  authorField.getText();
        boolean htmlChecked =  htmlCheckBox.isSelected();
        boolean controllerChecked =  controllerCheckBox.isSelected();
        boolean serviceChecked =  serviceCheckBox.isSelected();
        boolean modelChecked =  modelCheckBox.isSelected();

        businessGeneratorConfig.setProjectFolder(projectDir);
        businessGeneratorConfig.setHtmlFolder(htmlDir);
        businessGeneratorConfig.setHtml(htmlChecked);
        businessGeneratorConfig.setModel(modelChecked);
        businessGeneratorConfig.setControllerPackage(controllerPackage);
        businessGeneratorConfig.setControllerTargetProject(controllerTarget);
        businessGeneratorConfig.setController(controllerChecked);
        businessGeneratorConfig.setServicePackage(servicePackage);
        businessGeneratorConfig.setServiceTargetProject(serviceTarget);
        businessGeneratorConfig.getServiceConfig().setMapperPackage(daoPackage);
        businessGeneratorConfig.getServiceConfig().setMapperFullName(daoFullName);
        businessGeneratorConfig.getServiceConfig().setMapperName(daoName);
        businessGeneratorConfig.getServiceConfig().setMapperHumpName(com.roin.util.code.generator.util.StringUtils.toLowerCaseFirstChar(daoName));
        businessGeneratorConfig.setService(serviceChecked);
        businessGeneratorConfig.setModelPackage(modelPackage);
        businessGeneratorConfig.setModelHumpName(com.roin.util.code.generator.util.StringUtils.toLowerCaseFirstChar(modelName));
        businessGeneratorConfig.setModelName(modelName);
        businessGeneratorConfig.setModelSnakeName(com.roin.util.code.generator.util.StringUtils.humpToLine(modelName));
        businessGeneratorConfig.setModelFullName(modelFullName);
        businessGeneratorConfig.setModule(module);
        businessGeneratorConfig.setAuthor(author);
    }
    
    /**
     * HTML目录选择事件
     */
    @FXML
    public void chooseHtmlFolder() {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        String path = htmlFolderField.getText();
        if (!StringUtils.isEmpty(path)){
            File file = new File(path);
            if (file.exists())
                directoryChooser.setInitialDirectory(file);
        }
        File selectedFolder = directoryChooser.showDialog(getPrimaryStage());
        if (selectedFolder != null) {
            htmlFolderField.setText(selectedFolder.getAbsolutePath());
        }
    }

    /**
     * 打开Html配置窗口
     */
    @FXML
    public void openHtmlConfigFrame() {
        if (tableName == null) {
            AlertUtil.showWarnAlert("请先在左侧选择数据库表");
            return;
        }
        HtmlConfigController controller = (HtmlConfigController) loadFXMLPage("Html配置", FXMLPage.HTML_CONFIG, true);
        try {
            // If select same schema and another table, update table data
            if (!tableName.equalsIgnoreCase(businessGeneratorConfig.getHtmlConfig().getTableName())){
                businessGeneratorConfig.getHtmlConfig().setColumns(getHtmlConfigColumns());
                businessGeneratorConfig.getHtmlConfig().setTableName(tableName);
            }
            controller.setConfig(businessGeneratorConfig.getHtmlConfig());
            controller.showDialogStage();
        } catch (Exception e) {
            _LOG.error(e.getMessage(), e);
            AlertUtil.showErrorAlert(e.getMessage());
        }

    }

    private List<HtmlConfigColumn> getHtmlConfigColumns() throws Exception {
        List<UITableColumnVO> tableColumns = DbUtil.getTableColumns(selectedDatabaseConfig, tableName);
        List<HtmlConfigColumn> columns = new ArrayList<>();
        for (UITableColumnVO tableColumn : tableColumns) {
            HtmlConfigColumn column = new HtmlConfigColumn();
            column.setField(com.roin.util.code.generator.util.StringUtils.lineToHump(tableColumn.getColumnName()));
            column.setTitle(column.getField());
            columns.add(column);
        }
        return columns;
    }

    /**
     * 打开Controller配置窗口
     */
    @FXML
    public void openControllerConfigFrame() {
        if (tableName == null) {
            AlertUtil.showWarnAlert("请先在左侧选择数据库表");
            return;
        }
        ControllerConfigController controller = (ControllerConfigController) loadFXMLPage("Controller配置", FXMLPage.CONTROLLER_CONFIG, true);
        controller.setConfig(businessGeneratorConfig.getControllerConfig());
        controller.showDialogStage();
    }
}
